bitkeeper revision 1.1725 (42b7e4fcombAuDB0AR2i8hfnOEMfOQ)
authorcl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>
Tue, 21 Jun 2005 09:59:24 +0000 (09:59 +0000)
committercl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>
Tue, 21 Jun 2005 09:59:24 +0000 (09:59 +0000)
sched.h, xen.h, schedule.c, dom0_ops.c, hypercall.h, smpboot.c, process.c:
  Extend the CONFIG_HOTPLUG_CPU behavior down into the hypervisor.
  Adds two SCHEDOPS (vcpu_down/vcpu_up) which set/clear VCPU flag VCPU_down.
  The domain_runnable() check now looks at this flag and subsequently the
  vcpu is not scheduled when VCPU_down is set.
Signed-off-by: Ryan Harper <ryanh@us.ibm.com>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c
linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c
linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/hypercall.h
xen/common/dom0_ops.c
xen/common/schedule.c
xen/include/public/xen.h
xen/include/xen/sched.h

index d428b2305f326372f32b9cf980f89aec5fc946bd..eba38c6579a6839296caa30016b44540b2f51fea 100644 (file)
@@ -154,8 +154,13 @@ void cpu_idle (void)
                                cpu_clear(cpu, cpu_idle_map);
                        rmb();
 
-                       if (cpu_is_offline(cpu))
+                       if (cpu_is_offline(cpu)) {
+#if defined(CONFIG_XEN) && defined(CONFIG_HOTPLUG_CPU)
+                               /* Tell hypervisor to take vcpu down. */
+                               HYPERVISOR_vcpu_down(cpu);
+#endif
                                play_dead();
+         }
 
                        irq_stat[cpu].idle_timestamp = jiffies;
                        xen_idle();
index 1956f9ceed5fa7ce1390a29cee4720fa652aa0f9..93952385329c53c0142f40609263b3d15d5facc6 100644 (file)
@@ -1397,6 +1397,10 @@ int __devinit __cpu_up(unsigned int cpu)
        }
 
 #ifdef CONFIG_HOTPLUG_CPU
+#ifdef CONFIG_XEN
+       /* Tell hypervisor to bring vcpu up. */
+       HYPERVISOR_vcpu_up(cpu);
+#endif
        /* Already up, and in cpu_quiescent now? */
        if (cpu_isset(cpu, smp_commenced_mask)) {
                cpu_enable(cpu);
index 13ab9c3fde84d9df44e2522e9921c41c7611589a..98b2b999fd3a7f3f4bfaabe25540efb691cc9ff8 100644 (file)
@@ -517,4 +517,35 @@ HYPERVISOR_boot_vcpu(
     return ret;
 }
 
+static inline int
+HYPERVISOR_vcpu_down(
+    int vcpu)
+{
+    int ret;
+    unsigned long ign1;
+    __asm__ __volatile__ (
+        TRAP_INSTR
+        : "=a" (ret), "=b" (ign1)
+       : "0" (__HYPERVISOR_sched_op),
+         "1" (SCHEDOP_vcpu_down | (vcpu << SCHEDOP_vcpushift))
+        : "memory" );
+
+    return ret;
+}
+
+static inline int
+HYPERVISOR_vcpu_up(
+    int vcpu)
+{
+    int ret;
+    unsigned long ign1;
+    __asm__ __volatile__ (
+        TRAP_INSTR
+        : "=a" (ret), "=b" (ign1)
+       : "0" (__HYPERVISOR_sched_op),
+         "1" (SCHEDOP_vcpu_up | (vcpu << SCHEDOP_vcpushift))
+        : "memory" );
+
+    return ret;
+}
 #endif /* __HYPERCALL_H__ */
index ec86fc1b6290421c55b38c999c830771a5c97251..705f27bbb4dbf7455424feb5cd80b3aecdde4460 100644 (file)
@@ -339,9 +339,14 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
          * - domain is marked as paused or blocked only if all its vcpus 
          *   are paused or blocked 
          * - domain is marked as running if any of its vcpus is running
+         * - only map vcpus that aren't down.  Note, at some point we may
+         *   wish to demux the -1 value to indicate down vs. not-ever-booted
+         *   
          */
         for_each_vcpu ( d, v ) {
-            op->u.getdomaininfo.vcpu_to_cpu[v->vcpu_id] = v->processor;
+            /* only map vcpus that are up */
+            if ( !(test_bit(_VCPUF_down, &v->vcpu_flags)) )
+                op->u.getdomaininfo.vcpu_to_cpu[v->vcpu_id] = v->processor;
             op->u.getdomaininfo.cpumap[v->vcpu_id]      = v->cpumap;
             if ( !(v->vcpu_flags & VCPUF_ctrl_pause) )
                 flags &= ~DOMFLAGS_PAUSED;
@@ -384,6 +389,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
         struct vcpu_guest_context *c;
         struct domain             *d;
         struct vcpu               *v;
+        int i;
 
         d = find_domain_by_id(op->u.getvcpucontext.domain);
         if ( d == NULL )
@@ -398,8 +404,16 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
             put_domain(d);
             break;
         }
+
+        /* find first valid vcpu starting from request. */
+        v = NULL;
+        for ( i = op->u.getvcpucontext.vcpu; i < MAX_VIRT_CPUS; i++ )
+        {
+            v = d->vcpu[i];
+            if ( v != NULL && !(test_bit(_VCPUF_down, &v->vcpu_flags)) )
+                break;
+        }
         
-        v = d->vcpu[op->u.getvcpucontext.vcpu];
         if ( v == NULL )
         {
             ret = -ESRCH;
index d3273a80e836193ddb3b476758c3f59b735b0961..c547731302da686059105e70a832fc58a4f171cf 100644 (file)
@@ -261,6 +261,40 @@ static long do_yield(void)
     return 0;
 }
 
+/* Mark target vcpu as non-runnable so it is not scheduled */
+static long do_vcpu_down(int vcpu)
+{
+    struct vcpu *target;
+    
+    if ( vcpu > MAX_VIRT_CPUS )
+        return -EINVAL;
+
+    target = current->domain->vcpu[vcpu];
+    if ( target == NULL )
+        return -ESRCH;
+    set_bit(_VCPUF_down, &target->vcpu_flags);
+
+    return 0;
+}
+
+/* Mark target vcpu as runnable and wake it */
+static long do_vcpu_up(int vcpu)
+{
+    struct vcpu *target;
+   
+    if (vcpu > MAX_VIRT_CPUS)
+        return -EINVAL;
+
+    target = current->domain->vcpu[vcpu];
+    if ( target == NULL )
+        return -ESRCH;
+    clear_bit(_VCPUF_down, &target->vcpu_flags);
+    /* wake vcpu */
+    domain_wake(target);
+
+    return 0;
+}
+
 /*
  * Demultiplex scheduler-related hypercalls.
  */
@@ -290,6 +324,16 @@ long do_sched_op(unsigned long op)
         domain_shutdown((u8)(op >> SCHEDOP_reasonshift));
         break;
     }
+    case SCHEDOP_vcpu_down:
+    {
+        ret = do_vcpu_down((int)(op >> SCHEDOP_vcpushift));
+        break;
+    }
+    case SCHEDOP_vcpu_up:
+    {
+        ret = do_vcpu_up((int)(op >> SCHEDOP_vcpushift));
+        break;
+    }
 
     default:
         ret = -ENOSYS;
index 8b183491a6f7856556c58d008dec8fdbd87061b0..cef89b837ee9213776f1359cbd729553415340fc 100644 (file)
@@ -58,7 +58,7 @@
 #define __HYPERVISOR_boot_vcpu            24
 #define __HYPERVISOR_set_segment_base     25 /* x86/64 only */
 #define __HYPERVISOR_mmuext_op            26
-#define __HYPERVISOR_policy_op           27
+#define __HYPERVISOR_policy_op            27
 
 /* 
  * VIRTUAL INTERRUPTS
@@ -201,8 +201,11 @@ struct mmuext_op {
 #define SCHEDOP_yield           0   /* Give up the CPU voluntarily.       */
 #define SCHEDOP_block           1   /* Block until an event is received.  */
 #define SCHEDOP_shutdown        2   /* Stop executing this domain.        */
+#define SCHEDOP_vcpu_down       3   /* make target VCPU not-runnable.     */
+#define SCHEDOP_vcpu_up         4   /* make target VCPU runnable.         */
 #define SCHEDOP_cmdmask       255   /* 8-bit command. */
 #define SCHEDOP_reasonshift     8   /* 8-bit reason code. (SCHEDOP_shutdown) */
+#define SCHEDOP_vcpushift       8   /* 8-bit VCPU target. (SCHEDOP_up|down) */
 
 /*
  * Reason codes for SCHEDOP_shutdown. These may be interpreted by control 
index 7649f1a450716280ac0821b20b29043248ae4be6..ca21c5eee8c5f2856139673760e644efc3c5f188 100644 (file)
@@ -348,6 +348,9 @@ extern struct domain *domain_list;
  /* Initialization completed. */
 #define _VCPUF_initialised     8
 #define VCPUF_initialised      (1UL<<_VCPUF_initialised)
+ /* VCPU is not-runnable */
+#define _VCPUF_down            9
+#define VCPUF_down             (1UL<<_VCPUF_down)
 
 /*
  * Per-domain flags (domain_flags).
@@ -377,7 +380,7 @@ extern struct domain *domain_list;
 static inline int domain_runnable(struct vcpu *v)
 {
     return ( (atomic_read(&v->pausecnt) == 0) &&
-             !(v->vcpu_flags & (VCPUF_blocked|VCPUF_ctrl_pause)) &&
+             !(v->vcpu_flags & (VCPUF_blocked|VCPUF_ctrl_pause|VCPUF_down)) &&
              !(v->domain->domain_flags & (DOMF_shutdown|DOMF_shuttingdown)) );
 }